/*
 * =====================================================================================
 *
 *       Filename:  thread_server.c
 *
 *    Description:  多线程时调用epoll_wait测试
 *
 *        Version:  1.0
 *        Created:  2019年02月26日 19时35分25秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <libnyb/libnyb-net.h>
#include <pthread.h>

int fd_epoll = -1;

int epoll_new(void)
{

    int fd = epoll_create(1);
    if(fd < 0) {
        perror("epoll_create()");
        return -1;
    }
    return fd;

}

int create_set_udpsock(const char *ip, unsigned short port)
{
    int fd = udpsock_create(ip, port);
    if(fd < 0) {
        return -1;
    }
    if(sock_set_nonblock(fd) < 0) {
        close(fd);
        return -1;
    }
    if(sock_set_reuseaddr(fd) < 0) {
        close(fd);
        return -1;
    }
    return fd; 
}

int epoll_add_fd(int fd_epoll, int fd, int mode)
{
    struct epoll_event event;
    event.data.fd = fd;
    event.events = mode;
    epoll_ctl(fd_epoll, EPOLL_CTL_ADD, fd, &event);
}


int epoll_del_fd(int fd_epoll, int fd)
{
    epoll_ctl(fd_epoll, EPOLL_CTL_DEL, fd, NULL);
}

void read_data(const char *comment)
{
#define MAX_EVENTS 1
    int ret;
    struct epoll_event events[MAX_EVENTS];
    while(1) {
        ret = epoll_wait(fd_epoll, events, MAX_EVENTS, -1);
        if(ret <= 0) {
            perror("epoll_wait()");
            continue;
        }

        int i;
        for(i = 0; i < ret; i++) {
            if(events[i].events & EPOLLIN) {
                char buf[2046] = {0};
                struct sockaddr_in from;
                memset(&from, 0, sizeof(from));
                socklen_t fromlen = sizeof(struct sockaddr_in);
                ssize_t length = recvfrom(events[i].data.fd, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen);
                if(length >= 0) {
                    printf("%s receive from [%s:%d] length=%ld\n",
                            comment, inet_ntoa(from.sin_addr), ntohs(from.sin_port), length);
                }
                else {
                    perror("recvfrom()");
                }
            }

        }
    }
}

void thread1(void *arg)
{
    pthread_detach(pthread_self());
    read_data("Child");
    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    fd_epoll = epoll_new();
    if(fd_epoll < 0) {
        return 0;
    }

    int fd1 = create_set_udpsock("0.0.0.0", 22222);
    if(fd1 < 0) {
        return 0;
    }
    int fd2 = create_set_udpsock("0.0.0.0", 33333);
    if(fd2 < 0) {
        return 0;
    }

    epoll_add_fd(fd_epoll, fd1, EPOLLIN);
    epoll_add_fd(fd_epoll, fd2, EPOLLIN);

    pthread_t th;
    pthread_create(&th, NULL, (void *)&thread1, NULL);
    read_data("Father");
    return 0;
}


